package com.top.up.aspect;

import com.top.up.annotation.CheckParam;
import com.top.up.core.execption.CommonException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.validation.ConstraintViolation;
import javax.validation.Payload;
import javax.validation.Validation;
import javax.validation.Validator;
import java.lang.reflect.Method;
import java.util.*;

@Aspect
@Slf4j
@Component
public class CheckParamAspect {

    @Pointcut("@annotation(com.top.up.annotation.CheckParam)")
    public void deCut(){}

    @Before("deCut()")
    public void before(JoinPoint point){
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        //获取方法上的注解
        CheckParam checkParam = method.getAnnotation(CheckParam.class);
        String field = checkParam.field();
        List<String> fields = Arrays.asList(field);
        Object[] args = point.getArgs();

        fields.forEach(f -> {
            valid(args[Integer.valueOf(f)]);
        });
    }

    private void valid(Object arg) {
        //调用JSR303验证工具，校验参数
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<Object>> violations = validator.validate(arg);
        Iterator<ConstraintViolation<Object>> iter = violations.iterator();
        if (iter.hasNext()) {
            ConstraintViolation<Object> next = iter.next();
            Set<Class<? extends Payload>> payload = next.getConstraintDescriptor().getPayload();
            if(valid(arg, payload)){
                String errMessage = next.getMessage();
                log.error("参数校验失败" + errMessage);
                throw new CommonException("9998", errMessage);
            }
        }
    }

    private boolean valid(Object arg,Set<Class<? extends Payload>> payload){
        if(Objects.isNull(payload)||payload.size()==0)
            return true;
        for(Class p:payload){
            boolean valid;
            try {
                valid = p.newInstance().equals(arg);
            } catch (Exception e) {
                return true;
            }
            if(!valid){
                return valid;
            }
        }
        return true;
    }


}
